package com.xy.biz.xd.service.impl;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.fd.client.DocumentClient;
import com.xy.biz.fd.client.DocumentCodePoolClient;
import com.xy.biz.fd.client.DocumentCodeRuleClient;
import com.xy.biz.fd.domain.DocumentPermissions;
import com.xy.biz.fd.domain.enums.DocumentDefaultRepositoryEnum;
import com.xy.biz.fd.domain.req.SaveDocumentCodePoolRequest;
import com.xy.biz.fd.domain.req.document.SaveDocumentRequest;
import com.xy.biz.fd.domain.req.documentCode.GetDocumentCodeRuleRequest;
import com.xy.biz.fd.domain.resp.GetDocumentCodeRuleResponse1;
import com.xy.biz.mc.client.MessagePushClient;
import com.xy.biz.mc.domain.Message;
import com.xy.biz.mc.domain.consts.MessageTypeConstant;
import com.xy.biz.mc.domain.req.MessagePushRequest;
import com.xy.biz.uc.client.UserClient;
import com.xy.biz.uc.domain.dto.UserDTO;
import com.xy.biz.uc.domain.req.ListUserGroupByIdsRequest;
import com.xy.biz.xd.domain.bo.DocumentFlowBO;
import com.xy.biz.xd.domain.bo.DocumentFlowHandleBO;
import com.xy.biz.xd.domain.bo.DocumentFlowNewAndModifyBO;
import com.xy.biz.xd.domain.bo.DocumentReleaseBO;
import com.xy.biz.xd.domain.converter.DocumentFlowNewAndModifyConverter;
import com.xy.biz.xd.domain.enums.DocumentFlowBatchTypeEnum;
import com.xy.biz.xd.domain.enums.DocumentReleaseStatusEnum;
import com.xy.biz.xd.domain.query.DocumentFlowHandleQuery;
import com.xy.biz.xd.domain.query.DocumentFlowNewAndModifyQuery;
import com.xy.biz.xd.domain.query.DocumentFlowQuery;
import com.xy.biz.xd.domain.query.DocumentReleaseQuery;
import com.xy.biz.xd.domain.req.*;
import com.xy.biz.xd.domain.resp.ListDocumentFlowNewAndModifyResponse;
import com.xy.biz.xd.manager.DocumentFlowHandleManager;
import com.xy.biz.xd.manager.DocumentFlowManager;
import com.xy.biz.xd.manager.DocumentFlowNewAndModifyManager;
import com.xy.biz.xd.manager.DocumentReleaseManager;
import com.xy.biz.xd.service.DocumentFlowNewAndModifyService;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.tuples.Triple;
import com.xy.lang.util.CalendarUtils;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.gid.service.GidService;
import com.xy.tool.json.JsonUtils;
import com.xy.tool.util.BeanUtilsEx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.xy.biz.fd.domain.DocumentPermissions.PREVIEW;
import static com.xy.biz.fd.domain.DocumentPermissions.VISIBLE;
import static com.xy.biz.xd.domain.bo.DocumentFlowConstants.*;
import static com.xy.biz.xd.domain.bo.DocumentReleaseBO.*;
import static java.util.stream.Collectors.toList;

public abstract class AbstractDocumentFlowNewAndModifyServiceImpl implements DocumentFlowNewAndModifyService {

    @Autowired
    private GidService gidService;
    @Autowired
    private UserClient userClient;
    @Autowired
    private DocumentClient documentClient;
    @Autowired
    private MessagePushClient messagePushClient;
    @Autowired
    private DocumentFlowManager documentFlowManager;
    @Autowired
    private DocumentReleaseManager documentReleaseManager;
    @Autowired
    private DocumentCodeRuleClient documentCodeRuleClient;
    @Autowired
    private DocumentCodePoolClient documentCodePoolClient;
    @Autowired
    private DocumentFlowHandleManager documentFlowHandleManager;
    @Autowired
    private DocumentFlowServiceSupport documentFlowServiceSupport;
    @Autowired
    private DocumentFlowNewAndModifyManager documentFlowNewAndModifyManager;

    protected abstract String getType();

    @Transactional
    @Override
    public Result<?> applyApprovalDocumentFlow(HandleDocumentFlowRequest request) {
        DocumentFlowNewAndModifyBO documentFlowNewAndModifyBO = documentFlowNewAndModifyManager.getDocumentFlowNewAndModify(request.getDocumentFlowId());
        if (Objects.isNull(documentFlowNewAndModifyBO)) {
            return Result.ofNotFound(String.valueOf(request.getDocumentFlowId()));
        }
        if (Objects.equals(HANDLE_RESULT_ACCEPT, request.getResult())) {
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(
                    documentFlowNewAndModifyBO,
                    UserContextHolder.getUserId(),
                    PHASE_APPLY_APPROVAL,
                    HANDLE_RESULT_ACCEPT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Collections.singletonList(documentFlowHandleBO));
            documentFlowNewAndModifyBO.setPhase(
                    documentFlowNewAndModifyBO.getFlowType() == FLOW_TYPE_NEW ? PHASE_EDIT : PHASE_UPLOAD);
            documentFlowServiceSupport.gotoNextTask(documentFlowNewAndModifyBO, request.getNextHandleUserId(), request.getResult());
        } else {
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(
                    documentFlowNewAndModifyBO,
                    UserContextHolder.getUserId(),
                    PHASE_APPLY_APPROVAL,
                    HANDLE_RESULT_END, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Collections.singletonList(documentFlowHandleBO));
            documentFlowNewAndModifyBO.setPhase(PHASE_REJECT);
            documentFlowServiceSupport.gotoNextTask(documentFlowNewAndModifyBO, null, request.getResult());

            GetDocumentCodeRuleResponse1 response1 = ResultUtils.get(documentCodeRuleClient.getCodeInfo(GetDocumentCodeRuleRequest.builder().code(documentFlowNewAndModifyBO.getDocumentCode()).build()));
            if (Objects.isNull(response1)) {
                return Result.fail();
            }
            LocalDateTime now = LocalDateTime.now();
            if (documentFlowNewAndModifyBO.getBatchType().equals(DocumentFlowBatchTypeEnum.BATCH_PARENT.getCode())) {
                List<SaveDocumentCodePoolRequest> documentCodePoolRequestList = new ArrayList<>();
                List<DocumentFlowBO> documentFlowBOList = documentFlowManager.listDocumentFlow(
                        DocumentFlowQuery.max()
                                .parentDocumentFlowId(documentFlowNewAndModifyBO.getDocumentFlowId())
                                .batchType(DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode())
                                .build());
                documentFlowBOList.forEach(e -> documentCodePoolRequestList.add(SaveDocumentCodePoolRequest
                        .builder()
                        .documentCode(e.getDocumentCode())
                        .reuseFlag(true)
                        .updateTime(now)
                        .build()));
                documentCodePoolClient.updateAllDocumentCodePoolByCode(documentCodePoolRequestList);
            } else {
                SaveDocumentCodePoolRequest req = SaveDocumentCodePoolRequest.builder()
                        .documentCode(documentFlowNewAndModifyBO.getDocumentCode())
                        .reuseFlag(true)
                        .updateTime(now)
                        .build();
                documentCodePoolClient.updateDocumentCodePool(req);
            }
        }
        int row = documentFlowNewAndModifyManager.updateDocumentFlowNewAndModify(documentFlowNewAndModifyBO);
        if (row > 0) {
            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .path(MessageTypeConstant.FLOW_LIST)
                    .build();
            //定义发送给谁
            Long toId;
            //通过的信息
            if (Objects.equals(HANDLE_RESULT_ACCEPT, request.getResult())) {
                if (documentFlowNewAndModifyBO.getFlowType() == FLOW_TYPE_NEW) {
                    message.setRemark("新增流程-编辑");
                } else {
                    message.setRemark("新增流程-上传模板");
                }
                message.setData(1);
                toId = request.getNextHandleUserId();
            } else {//不通过的信息
                message.setRemark("新增流程-流程审批拒绝申请");
                message.setData(0);
                //获取申请人
                toId = getApplyUserId(request.getDocumentFlowId(), PHASE_APPLY);
            }
            //发送消息
            sendMessage(message, toId);
        }
        return Result.success();
    }

    @Transactional
    @Override
    public Result<?> editDocumentFlow(EditDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());
        DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(
                documentFlowBO,
                UserContextHolder.getUserId(),
                PHASE_EDIT,
                HANDLE_RESULT_ACCEPT,
                request.getOpinion());
        documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
        List<Long> reviewUserIdList = request.getReviewUserIdList();
        documentFlowServiceSupport.gotoNextTask2(documentFlowBO, reviewUserIdList, HANDLE_RESULT_ACCEPT);
        documentFlowBO.setPhase(PHASE_REVIEW);
        documentFlowBO.setUpdateTime(now);
        documentFlowManager.updateDocumentFlow(documentFlowBO);
        documentFlowNewAndModifyManager.updateReviewerNum(documentFlowBO, reviewUserIdList.size());
        //发送消息

        //定义消息内容
        Message message = Message.builder()
                .type(MessageTypeConstant.TYPE_FLOW)
                .data(1)
                .remark(getType() + "流程-文件评审")
                .path(MessageTypeConstant.FLOW_LIST)
                .build();
        //发送消息
        for (Long reviewUserId : request.getReviewUserIdList()) {
            sendMessage(message, reviewUserId);
        }
        return Result.success();
    }

    @Transactional
    @Override
    public synchronized Result<?> reviewDocumentFlow(ReviewDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());

        Long editUserId = documentFlowServiceSupport.getEditor(documentFlowBO, PHASE_EDIT);
        DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_REVIEW, HANDLE_RESULT_ACCEPT, request.getOpinion());
        documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
        documentFlowServiceSupport.gotoNextTask(documentFlowBO, editUserId, HANDLE_RESULT_ACCEPT);

        int count = documentFlowNewAndModifyManager.getReviewerNum(documentFlowBO);
        int reviewedCount = documentFlowServiceSupport.getHandleCountForPhaseAndResult(documentFlowBO, PHASE_REVIEW, HANDLE_RESULT_ACCEPT);
        if (reviewedCount >= count) {
            documentFlowBO.setPhase(PHASE_EDIT_AGAIN);
        }
        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);

        if (row > 0 && reviewedCount == count) {
            //获取申请人 文件编辑人员
            Long applyUserId = getApplyUserId(request.getDocumentFlowId(), PHASE_EDIT);

            //发送消息

            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .data(1)
                    .remark(getType() + "流程-再次编辑")
                    .path(MessageTypeConstant.FLOW_LIST)
                    .build();

            sendMessage(message, applyUserId);
        }

        return Result.success();
    }

    @Transactional
    @Override
    public Result<?> editAgainDocumentFlow(EditAgainDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());
        DocumentFlowHandleBO documentFlowHandleBO;
        if (Objects.equals(HANDLE_RESULT_REJECT, request.getResult())) {
            documentFlowHandleBO = DocumentFlowHandleBO.build(
                    documentFlowBO, UserContextHolder.getUserId(), PHASE_EDIT_AGAIN, HANDLE_RESULT_REJECT, request.getOpinion());
            List<Long> reviewUserIdList = request.getReviewUserIdList();
            documentFlowServiceSupport.gotoNextTask2(documentFlowBO, reviewUserIdList, HANDLE_RESULT_REJECT);
            documentFlowBO.setPhase(PHASE_REVIEW);
            documentFlowNewAndModifyManager.updateReviewerNum(documentFlowBO, reviewUserIdList.size());
        } else {
            documentFlowHandleBO = DocumentFlowHandleBO.build(
                    documentFlowBO, UserContextHolder.getUserId(), PHASE_EDIT_AGAIN, HANDLE_RESULT_ACCEPT, request.getOpinion());
            documentFlowBO.setPhase(PHASE_FORMAT_AUDIT);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, request.getAuditUserId(), HANDLE_RESULT_ACCEPT);

        }
        documentFlowHandleManager.saveAllDocumentFlowHandle(Collections.singletonList(documentFlowHandleBO));
        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);

        if (row > 0) {
            //发送消息
            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .data(1)
                    .path(MessageTypeConstant.FLOW_LIST)
                    .build();
            if (Objects.equals(HANDLE_RESULT_REJECT, request.getResult())) {
                message.setRemark(getType() + "流程-文件评审");
                for (Long reviewUserId : request.getReviewUserIdList()) {
                    sendMessage(message, reviewUserId);
                }
            } else {
                message.setRemark(getType() + "流程-格式审核");
                sendMessage(message, request.getAuditUserId());
            }
        }
        return Result.success();
    }

    @Override
    public Result<?> formatAuditDocumentFlow(HandleDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());

        if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_FORMAT_AUDIT, HANDLE_RESULT_ACCEPT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_CONTENT_AUDIT);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, request.getNextHandleUserId(), HANDLE_RESULT_ACCEPT);
        } else {
            //获取上一个handleUser
            DocumentFlowHandleBO lastDocumentFlowHandleBO = documentFlowServiceSupport.getLastPhaseHandleUser(documentFlowBO, PHASE_EDIT_AGAIN);
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_FORMAT_AUDIT, HANDLE_RESULT_REJECT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_EDIT_AGAIN);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, lastDocumentFlowHandleBO.getHandleUserId(), HANDLE_RESULT_REJECT);
        }
        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);
        if (row > 0) {
            //发送消息
            //通过
            if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-内容审核")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, request.getNextHandleUserId());
            } else {//拒绝通过
                //获取申请用户id  查找再次编辑人员
                Long applyUserId = getApplyUserId(request.getDocumentFlowId(), PHASE_EDIT_AGAIN);
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-再次编辑-格式审核不通过")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, applyUserId);
            }

        }

        return Result.success();
    }

    @Transactional
    @Override
    public Result<?> contentAuditDocumentFlow(HandleDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());

        if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_CONTENT_AUDIT, HANDLE_RESULT_ACCEPT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_APPROVAL);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, request.getNextHandleUserId(), HANDLE_RESULT_ACCEPT);
        } else {
            // 获取再次编辑的HandlerUser
            DocumentFlowHandleBO lastDocumentFlowHandleBO = documentFlowServiceSupport.getLastPhaseHandleUser(documentFlowBO, PHASE_EDIT_AGAIN);
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_CONTENT_AUDIT, HANDLE_RESULT_REJECT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_EDIT_AGAIN);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, lastDocumentFlowHandleBO.getHandleUserId(), HANDLE_RESULT_REJECT);
        }
        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);
        if (row > 0) {
            //发送消息
            //通过
            if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-文件审批")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, request.getNextHandleUserId());
            } else {//拒绝通过
                //获取申请用户id  查找格式审核人
                Long applyUserId = getApplyUserId(request.getDocumentFlowId(), PHASE_FORMAT_AUDIT);
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-格式审核-文件审核不通过")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, applyUserId);
            }

        }
        return Result.success();
    }

    @Transactional
    @Override
    public Result<?> approvalDocumentFlow(HandleDocumentFlowRequest request) {
        LocalDateTime now = LocalDateTime.now();

        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());

        if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_APPROVAL, HANDLE_RESULT_ACCEPT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_RELEASE);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, request.getNextHandleUserId(), HANDLE_RESULT_ACCEPT);
        } else {
            DocumentFlowHandleBO lastDocumentFlowHandleBO = documentFlowServiceSupport.getLastPhaseHandleUser(documentFlowBO, PHASE_EDIT_AGAIN);
            DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_APPROVAL, HANDLE_RESULT_REJECT, request.getOpinion());
            documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
            documentFlowBO.setPhase(PHASE_EDIT_AGAIN);
            documentFlowServiceSupport.gotoNextTask(documentFlowBO, lastDocumentFlowHandleBO.getHandleUserId(), HANDLE_RESULT_REJECT);
        }

        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);
        if (row > 0) {
            //发送消息
            //通过
            if (Objects.equals(request.getResult(), HANDLE_RESULT_ACCEPT)) {
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-文件放行")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, request.getNextHandleUserId());
            } else {//拒绝通过
                //获取申请用户id  查找文件审核人
                Long applyUserId = getApplyUserId(request.getDocumentFlowId(), PHASE_CONTENT_AUDIT);
                //发送消息

                //定义消息内容
                Message message = Message.builder()
                        .type(MessageTypeConstant.TYPE_FLOW)
                        .data(1)
                        .remark(getType() + "流程-文件审核-文件审批不通过")
                        .path(MessageTypeConstant.FLOW_LIST)
                        .build();
                sendMessage(message, applyUserId);
            }
        }
        return Result.success();
    }

    @Override
    public Result<?> getDocumentFlowNewAndModify(Long documentFlowId) {
        DocumentFlowNewAndModifyBO documentFlowNewAndModify = documentFlowNewAndModifyManager.getDocumentFlowNewAndModify(documentFlowId);
        if (Objects.isNull(documentFlowNewAndModify)) {
            return Result.fail("", "当前流程不存在！");
        }
        if (Objects.equals(DocumentFlowBatchTypeEnum.BATCH_PARENT.getCode(), documentFlowNewAndModify.getBatchType())) {
            List<DocumentFlowNewAndModifyBO> documentFlowNewAndModifyBOList = documentFlowNewAndModifyManager.listDocumentFlowNewAndModify(DocumentFlowNewAndModifyQuery.max()
                    .parentDocumentFlowId(documentFlowNewAndModify.getDocumentFlowId())
                    .batchType(DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode())
                    .build());
            ListDocumentFlowNewAndModifyResponse listDocumentFlowNewAndModifyResponse = DocumentFlowNewAndModifyConverter.toResponseList(documentFlowNewAndModify);
            listDocumentFlowNewAndModifyResponse.setDocumentFlowInfoList(DocumentFlowNewAndModifyConverter.toResponseList(documentFlowNewAndModifyBOList));
            buildFileExtension(listDocumentFlowNewAndModifyResponse);
            return Result.success(listDocumentFlowNewAndModifyResponse);
        } else {
            ListDocumentFlowNewAndModifyResponse listDocumentFlowNewAndModifyResponse = DocumentFlowNewAndModifyConverter.toResponseList(documentFlowNewAndModify);
            listDocumentFlowNewAndModifyResponse.setDocumentFlowInfoList(DocumentFlowNewAndModifyConverter.toResponseList(Collections.singleton(documentFlowNewAndModify)));
            buildFileExtension(listDocumentFlowNewAndModifyResponse);
            return Result.success(listDocumentFlowNewAndModifyResponse);
        }
    }

    private void buildFileExtension(ListDocumentFlowNewAndModifyResponse response) {
        List<ListDocumentFlowNewAndModifyResponse.DocumentFlowInfo> documentFlowInfoList = response.getDocumentFlowInfoList();
        documentClient.buildByDocument(documentFlowInfoList,
                documentFlowInfoList.stream().map(ListDocumentFlowNewAndModifyResponse.DocumentFlowInfo::getDocumentId).collect(Collectors.toSet()),
                ListDocumentFlowNewAndModifyResponse.DocumentFlowInfo::getDocumentId,
                (documentFlowInfo, document) -> documentFlowInfo.setFileExtension(document.getFileExtension()));
    }

    @Override
    public List<DocumentFlowNewAndModifyBO> listDocumentFlowNewAndModify(DocumentFlowNewAndModifyQuery query) {
        List<DocumentFlowNewAndModifyBO> documentFlowNewAndModifyBOList = documentFlowNewAndModifyManager.listDocumentFlowNewAndModify(query);
        if (CollectionUtils.isEmpty(documentFlowNewAndModifyBOList)) {
            return Collections.emptyList();
        }
        Set<Long> documentFlowIdSet = new HashSet<>();
        documentFlowNewAndModifyBOList.forEach(doc -> {
            doc.setAccessTimeString(CalendarUtils.getDeadlineString(doc.getUpdateTime(), LocalDateTime.now()));
            documentFlowIdSet.add(doc.getDocumentFlowId());
        });
        //过滤掉未生效的流程信息
        Map<Long, List<DocumentReleaseBO>> documentReleaseGroup = documentReleaseManager.listAllDocumentRelease(
                        DocumentReleaseQuery.max().documentFlowIdList(new ArrayList<>(documentFlowIdSet)).build())
                .stream().collect(Collectors.groupingBy(DocumentReleaseBO::getDocumentFlowId));
        documentFlowNewAndModifyBOList = documentFlowNewAndModifyBOList.stream()
                .filter(e -> {
                    if (documentReleaseGroup.containsKey(e.getDocumentFlowId())) {
                        return documentReleaseGroup.get(e.getDocumentFlowId()).get(0).getEffectFlag();
                    }
                    return false;
                })
                .collect(toList());
        Collections.sort(documentFlowNewAndModifyBOList, (e1, e2) -> e2.getUpdateTime().compareTo(e1.getUpdateTime()));
        return documentFlowNewAndModifyBOList;
    }

    @Override
    public int countDocumentFlowNewAndModify(DocumentFlowNewAndModifyQuery query) {
        return documentFlowNewAndModifyManager.countDocumentFlowNewAndModify(query);
    }

    /**
     * 获取申请用户id
     * @param documentFlowId
     * @return
     */
    protected Long getApplyUserId(Long documentFlowId, String phase) {
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(DocumentFlowHandleQuery.builder()
                .documentFlowId(documentFlowId)
                .phase(phase)
                .build());
        DocumentFlowHandleBO documentFlowHandleBO1 = documentFlowHandleBOS.get(0);
        return documentFlowHandleBO1.getHandleUserId();
    }
/**
 * 撤回
 * @param request
 * @author zgy
 * @description 撤回流程
 * @return
 *//*
    @Override
    public Result<?> withdraw(HandleDocumentFlowRequest request) {
        // 查看是否已进入下一流程
        //根据流程ID和当前登录用户查找我处理过的本流程节点
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(DocumentFlowHandleQuery.builder().documentFlowId(request.getDocumentFlowId()).handleUserId(UserContextHolder.getUserId()).build());
        if (CollectionUtils.isEmpty(documentFlowHandleBOS)) {
            return Result.fail("无此流程数据！");
        }
        Collections.sort(documentFlowHandleBOS, Comparator.comparing(DocumentFlowHandleBO::getCreateTime, Comparator.reverseOrder()));
        //查看最新处理的数据是否为本节点
        DocumentFlowHandleBO documentFlowHandleBO = documentFlowHandleBOS.get(0);
        if (!documentFlowHandleBO.getPhase().equals(request.getPhase())) {
            return Result.fail("", "此流程已被处理，无法取消！");
        }
        LocalDateTime now = LocalDateTime.now();
        // 未进入下一流程，可执行取消操作
        DocumentFlowBO documentFlowBO = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());
        DocumentFlowHandleBO documentFlowHandleBO1 = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), request.getPhase(), HANDLE_RESULT_CANCEL, request.getOpinion());
        //记录取消操作
        documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO1));
        documentFlowBO.setPhase(request.getPhase());
        documentFlowServiceSupport.recall(documentFlowBO, request.getPhase());
        documentFlowBO.setUpdateTime(now);
        int row = documentFlowManager.updateDocumentFlow(documentFlowBO);
        return Result.success(row);
    }*/

    /*    private Result<?> getNode(HandleDocumentFlowRequest request) {
        //根据流程ID和当前登录用户查找我处理过的本流程节点
        List<DocumentFlowHandleBO> documentFlowHandleBOS = documentFlowHandleManager.listDocumentFlowHandle(DocumentFlowHandleQuery.builder().documentFlowId(request.getDocumentFlowId()).handleUserId(UserContextHolder.getUserId()).build());
        if (CollectionUtils.isEmpty(documentFlowHandleBOS)) {
            return Result.fail("无此流程数据！");
        }
        Collections.sort(documentFlowHandleBOS, Comparator.comparing(DocumentFlowHandleBO::getCreateTime, Comparator.reverseOrder()));
        //查看最新处理的数据是否为本节点
        if (!documentFlowHandleBOS.get(0).getPhase().equals(request.getPhase())) {
            return Result.fail("", "此流程已被处理，无法取消！");
        }
        return Result.success();
    }*/

    /**
     * 终止
     * @param request
     * @return
     */
    @Override
    public Result<?> termination(HandleDocumentFlowRequest request) {
        DocumentFlowBO documentFlow = documentFlowManager.getDocumentFlow(request.getDocumentFlowId());
        documentFlowServiceSupport.finish(documentFlow);
        //记录终止操作
        DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(
                documentFlow,
                UserContextHolder.getUserId(),
                documentFlow.getPhase(),
                HANDLE_RESULT_END, request.getOpinion());
        documentFlowHandleManager.saveAllDocumentFlowHandle(Arrays.asList(documentFlowHandleBO));
        LocalDateTime now = LocalDateTime.now();
        List<DocumentFlowBO> documentFlowBOList = new ArrayList<>();
        Set<Long> documentIdSet = new HashSet<>();
        Set<String> documentCodeSet = new HashSet<>();
        List<SaveDocumentCodePoolRequest> documentCodePoolRequestList = new ArrayList<>();
        if (!documentFlow.getBatchType().equals(DocumentFlowBatchTypeEnum.UNBATCH.getCode())) {
            documentFlowBOList = documentFlowManager.listDocumentFlow(DocumentFlowQuery
                    .max()
                    .parentDocumentFlowId(documentFlow.getDocumentFlowId())
                    .batchType(DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode())
                    .build());
            documentFlowBOList.forEach(e -> {
                documentIdSet.add(e.getDocumentId());
                documentCodeSet.add(e.getDocumentCode());
                documentCodePoolRequestList.add(SaveDocumentCodePoolRequest
                        .builder()
                        .documentCode(e.getDocumentCode())
                        .reuseFlag(true)
                        .updateTime(now)
                        .build());
                e.setUpdateTime(now);
                e.setPhase(PHASE_END);
            });
            documentFlowBOList.add(documentFlow);
        } else {
            documentFlow.setUpdateTime(now);
            documentFlow.setPhase(PHASE_END);
            documentCodeSet.add(documentFlow.getDocumentCode());
            documentCodePoolRequestList.add(SaveDocumentCodePoolRequest
                    .builder()
                    .documentCode(documentFlow.getDocumentCode())
                    .reuseFlag(true)
                    .updateTime(now)
                    .build());
            documentIdSet.add(documentFlow.getDocumentId());
            documentFlowBOList.add(documentFlow);
        }
        documentFlowManager.updateAllDocumentFlow(documentFlowBOList);
        //流程文件解锁
        documentClient.updateDocument(SaveDocumentRequest.builder().documentFlowLock(false).documentIds(new ArrayList<>(documentIdSet)).build());
        GetDocumentCodeRuleResponse1 response = ResultUtils.get(documentCodeRuleClient.getCodeInfo(GetDocumentCodeRuleRequest.builder().code(documentFlow.getDocumentCode()).build()));
        if (Objects.isNull(response)) {
            return Result.fail();
        }
        //终止的流程需要回收文件编码
        Integer row = ResultUtils.get(documentCodePoolClient.updateAllDocumentCodePoolByCode(documentCodePoolRequestList));
        //发送消息给流程申请人
        Long createUserId = documentFlow.getCreateUserId();
        String name = documentFlow.getDocumentName();
        //定义消息内容
        Message message = Message.builder()
                .type(MessageTypeConstant.TYPE_FLOW)
                .data(1)
                .remark(name + "-文件已被终止")
                .path(MessageTypeConstant.FLOW_LIST)
                .build();
        sendMessage(message, createUserId);
        return Result.success(row);
    }

    /**
     * 发送信息
     * @param message
     * @param toId
     */
    protected void sendMessage(Message message, Long toId) {
        messagePushClient.send(MessagePushRequest.builder()
                .data(JsonUtils.toJson(message).getBytes())
                .dataType(0)
                .expiredSeconds(0L)
                .toId(toId)
                .offlineFlag(true).build());
    }

    protected DocumentFlowNewAndModifyBO buildNewDocumentFlowBO(List<DocumentFlowNewAndModifyBO> documentFlowNewAndModifyBOList, Integer flowType) {
        Objects.requireNonNull(documentFlowNewAndModifyBOList);
        DocumentFlowNewAndModifyBO parentFlow;
        if (documentFlowNewAndModifyBOList.stream().allMatch(e -> e.getBatchType().equals(DocumentFlowBatchTypeEnum.UNBATCH.getCode()))) {
            documentFlowNewAndModifyBOList.forEach(e -> buildNewDocumentFlowNewAndModifyBO(e, flowType, DocumentFlowBatchTypeEnum.UNBATCH.getCode(), null));
            parentFlow = documentFlowNewAndModifyBOList.get(0);
        } else {
            parentFlow = BeanUtilsEx.copyProperties(documentFlowNewAndModifyBOList.get(0), DocumentFlowNewAndModifyBO::new);
            buildNewDocumentFlowNewAndModifyBO(parentFlow, flowType, DocumentFlowBatchTypeEnum.BATCH_PARENT.getCode(), null);
            parentFlow.setDocumentName(null);
            documentFlowNewAndModifyBOList.forEach(e -> {
                String documentName = Objects.isNull(parentFlow.getDocumentName()) ? "" : parentFlow.getDocumentName() + "，";
                parentFlow.setDocumentName(documentName.length() > 190 ? documentName.substring(0, 190) + "......" : documentName + e.getDocumentName());
                buildNewDocumentFlowNewAndModifyBO(e, flowType, DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode(), parentFlow.getDocumentFlowId());
            });
            documentFlowNewAndModifyBOList.add(parentFlow);
        }
        DocumentFlowHandleBO.build(parentFlow, UserContextHolder.getUserId(), PHASE_APPLY, HANDLE_RESULT_ACCEPT, parentFlow.getReason());
        return parentFlow;
    }

    private void buildNewDocumentFlowNewAndModifyBO(DocumentFlowNewAndModifyBO documentFlowNewAndModifyBO, Integer flowType, Integer batchType, Long parentDocumentFlowId) {
        LocalDateTime now = LocalDateTime.now();
        documentFlowNewAndModifyBO.setDocumentFlowId(gidService.generate());
        documentFlowNewAndModifyBO.setFlowType(flowType);
        documentFlowNewAndModifyBO.setPhase(PHASE_APPLY_APPROVAL);
        documentFlowNewAndModifyBO.setBatchType(batchType);
        documentFlowNewAndModifyBO.setParentDocumentFlowId(parentDocumentFlowId);
        if (Objects.isNull(documentFlowNewAndModifyBO.getDocumentId())) {
            documentFlowNewAndModifyBO.setDocumentId(0L);
        }
        documentFlowNewAndModifyBO.setTenantId(UserContextHolder.getTenantId());
        documentFlowNewAndModifyBO.setCreateUserId(UserContextHolder.getUserId());
        documentFlowNewAndModifyBO.setCreateUserName(UserContextHolder.getUserName());
        documentFlowNewAndModifyBO.setCreateUserGroupId(UserContextHolder.getUserGroupId());
        documentFlowNewAndModifyBO.setCreateUserGroupName(UserContextHolder.getUserGroupName());
        documentFlowNewAndModifyBO.setCreateTime(now);
        documentFlowNewAndModifyBO.setUpdateTime(now);
        documentFlowNewAndModifyBO.setPreviousDocumentId(0L);
        if (FLOW_TYPE_NEW == flowType) {
            documentFlowNewAndModifyBO.setPreviousDocumentVersion("");
        } else {
            documentFlowNewAndModifyBO.setPreviousDocumentVersion(documentFlowNewAndModifyBO.getPreviousDocumentVersion());
        }
        documentFlowNewAndModifyBO.setTrainFlag(false);
        documentFlowNewAndModifyBO.setTrainerUserId(0L);
        documentFlowNewAndModifyBO.setTrainCheckStatus(TRAIN_CHECK_STATUS_UNCHECK);
    }

    protected List<DocumentFlowNewAndModifyBO> buildUploadDocumentFlowNewAndModifyBO(DocumentFlowNewAndModifyBO documentFlowNewAndModifyBO, Map<String, Long> documentCodeMap, Map<String, Long> documentCodePreviousMap) {
        Objects.requireNonNull(documentFlowNewAndModifyBO.getDocumentFlowId());
        documentFlowNewAndModifyBO.setUpdateTime(LocalDateTime.now());
        List<DocumentFlowNewAndModifyBO> documentFlowNewAndModifyBOList = documentFlowNewAndModifyManager.listDocumentFlowNewAndModify(DocumentFlowNewAndModifyQuery
                .max()
                .batchType(DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode())
                .parentDocumentFlowId(documentFlowNewAndModifyBO.getDocumentFlowId())
                .build());
        Objects.requireNonNull(documentFlowNewAndModifyBOList);
        LocalDateTime now = LocalDateTime.now();
        documentFlowNewAndModifyBOList.add(documentFlowNewAndModifyBO);
        documentFlowNewAndModifyBOList.forEach(e -> {
            e.setDocumentId(documentCodeMap.get(e.getDocumentCode()));
            if (!CollectionUtils.isEmpty(documentCodePreviousMap)) {
                e.setPreviousDocumentId(documentCodePreviousMap.get(e.getDocumentCode()));
            }
            e.setUpdateTime(now);
        });
        return documentFlowNewAndModifyBOList;
    }

    protected List<Long> buildUserIdCollection(List<Long> userIdList, List<Long> userGroupIdList) {
        if (!CollectionUtils.isEmpty(userGroupIdList) && !CollectionUtils.isEmpty(userIdList)) {
            Set<Long> ids = ResultUtils.get(userClient.listUserByUserGroup(ListUserGroupByIdsRequest.builder()
                            .groupIds(userGroupIdList).build()))
                    .stream().map(UserDTO::getUserId).collect(Collectors.toSet());
            return userIdList.stream().filter(e -> !ids.contains(e)).collect(toList());
        }
        return userIdList;
    }

    protected SaveDocumentRequest buildRequest(DocumentFlowBO documentFlowBO, String opinion) {
        return SaveDocumentRequest.builder()
                .documentId(documentFlowBO.getDocumentId())
                .latestVersionFlag(0)
                .repositoryId(DocumentDefaultRepositoryEnum.CURRENT_REPOSITORY.getCode())
                .versionComment(opinion)
                .documentName(documentFlowBO.getDocumentName())
                .level(documentFlowBO.getDocumentLevel())
                .type(documentFlowBO.getDocumentProperty())
                .version(documentFlowBO.getDocumentVersion())
                .documentCode(documentFlowBO.getDocumentCode())
                .build();
    }

    protected Set<Long> buildMessageReceiveUserIdCollection(List<Long> userIdList, List<Long> userGroupIdList) {
        Set<Long> userIds = new HashSet<>();
        //获取需要发送信息的用户
        if (!CollectionUtils.isEmpty(userIdList)) {
            userIds.addAll(userIdList);
        }
        if (!CollectionUtils.isEmpty(userGroupIdList)) {
            Result<Collection<Long>> collectionResult = userClient.listUserIdByUserGroupId(userGroupIdList);
            if (collectionResult.wasSuccess()) {
                if (!CollectionUtils.isEmpty(collectionResult.getData())) {
                    userIds.addAll(collectionResult.getData());
                }
            }
        }
        return userIds;
    }

    protected Result<Triple<List<DocumentFlowNewAndModifyBO>, List<Long>, List<Long>>> saveDocumentReleaseList(ReleaseDocumentFlowNewAndModifyRequest request, DocumentFlowNewAndModifyBO documentFlowBO, Integer batchType) {
        DocumentFlowHandleBO documentFlowHandleBO = DocumentFlowHandleBO.build(documentFlowBO, UserContextHolder.getUserId(), PHASE_RELEASE, HANDLE_RESULT_ACCEPT, request.getOpinion());
        documentFlowHandleManager.saveAllDocumentFlowHandle(Collections.singletonList(documentFlowHandleBO));
        documentFlowServiceSupport.finishLastTask(documentFlowBO);
        List<DocumentFlowNewAndModifyBO> documentFlowList = new ArrayList<>();
        if (batchType.equals(DocumentFlowBatchTypeEnum.BATCH_PARENT.getCode())) {
            documentFlowList = documentFlowNewAndModifyManager.listDocumentFlowNewAndModify(DocumentFlowNewAndModifyQuery
                    .max()
                    .batchType(DocumentFlowBatchTypeEnum.BATCH_SUBFILE.getCode())
                    .parentDocumentFlowId(documentFlowBO.getDocumentFlowId())
                    .build());
            Objects.requireNonNull(documentFlowList);
        }
        if (batchType.equals(DocumentFlowBatchTypeEnum.UNBATCH.getCode())) {
            documentFlowList.add(documentFlowBO);
        }
        List<Long> receiveUserGroupIdList = request.getReceiveUserGroupIdList();
        List<Long> receiveUserIdList = buildUserIdCollection(request.getReceiveUserIdList(), receiveUserGroupIdList);
        List<DocumentReleaseBO> documentReleaseBOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(receiveUserIdList)) {
            for (DocumentFlowNewAndModifyBO e : documentFlowList) {
                for (Long receiveUserId : receiveUserIdList) {
                    documentReleaseBOList.add(buildDocumentReleaseBO(e, receiveUserId, RECEIVE_TYPE_USER, request.getEffectDate()));
                }
            }
        }
        if (!CollectionUtils.isEmpty(receiveUserGroupIdList)) {
            for (DocumentFlowNewAndModifyBO e : documentFlowList) {
                for (Long receiveUserGroupId : receiveUserGroupIdList) {
                    documentReleaseBOList.add(buildDocumentReleaseBO(e, receiveUserGroupId, RECEIVE_TYPE_USER_GROUP, request.getEffectDate()));
                }
            }
        }
        int row = documentReleaseManager.saveAllDocumentRelease(documentReleaseBOList);
        if (row > 0) {
            return Result.success(new Triple(documentFlowList, receiveUserIdList, receiveUserGroupIdList));
        }
        return Result.fail();
    }

    private DocumentReleaseBO buildDocumentReleaseBO(DocumentFlowBO documentFlowBO, Long receiveId, Integer receiveType,
                                                     LocalDate effectDate) {
        LocalDateTime now = LocalDateTime.now();
        return DocumentReleaseBO.builder()
                .receiveId(receiveId)
                .receiveType(receiveType)
                .status(STATUS_RELEASE)
                .permission(DocumentPermissions.addPermission(VISIBLE, PREVIEW))
                .documentId(documentFlowBO.getDocumentId())
                .documentCode(documentFlowBO.getDocumentCode())
                .documentName(documentFlowBO.getDocumentCode()
                        + " " + documentFlowBO.getDocumentName()
                        + "-(" + documentFlowBO.getDocumentVersion() + ")")
                .documentVersion(documentFlowBO.getDocumentVersion())
                .documentFlowId(documentFlowBO.getDocumentFlowId())
                .flowType(documentFlowBO.getFlowType())
                .documentLevel(documentFlowBO.getDocumentLevel())
                .documentProperty(documentFlowBO.getDocumentProperty())
                .tenantId(0L)
                .createUserId(UserContextHolder.getUserId())
                .createTime(now)
                .updateTime(now)
                .effectDate(effectDate)
                .build();
    }
}
